package com.javacv.plus.extensions.audio.steps;

import com.javacv.plus.core.processor.ProcessorContext;
import com.javacv.plus.core.processor.ProcessorStep;
import com.javacv.plus.extensions.audio.AudioProcessor;
import com.javacv.plus.extensions.audio.AudioResult;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import java.nio.Buffer;
import java.nio.ShortBuffer;

/**
 * 淡入淡出效果步骤
 */
@Slf4j
public class FadeStep implements ProcessorStep<AudioProcessor, AudioResult> {
    public enum FadeType {
        IN,
        OUT
    }

    private final FadeType type;
    private final double durationSeconds;

    public FadeStep(FadeType type, double durationSeconds) {
        this.type = type;
        this.durationSeconds = durationSeconds;
    }

    @Override
    public AudioResult execute(AudioProcessor processor, ProcessorContext context) throws Exception {
        log.info("Adding {} fade effect with duration: {}s", type, durationSeconds);

        FFmpegFrameGrabber grabber = (FFmpegFrameGrabber) context.getAttribute("grabber");
        try (FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(
                "temp_fade.mp3",
                grabber.getAudioChannels(),
                grabber.getSampleRate()
        )) {
            recorder.setFormat(grabber.getFormat());
            recorder.setAudioBitrate(grabber.getAudioBitrate());
            recorder.setAudioChannels(grabber.getAudioChannels());
            recorder.setSampleRate(grabber.getSampleRate());
            recorder.start();

            // 计算淡入淡出的帧数
            long fadeFrames = (long) (durationSeconds * grabber.getSampleRate());
            long totalFrames = 0;
            long currentFrame = 0;

            // 处理音频帧
            Frame frame;
            while ((frame = grabber.grab()) != null) {
                if (frame.samples != null) {
                    // 计算淡入淡出因子
                    double factor;
                    if (type == FadeType.IN) {
                        factor = Math.min(1.0, (double) currentFrame / fadeFrames);
                    } else {
                        factor = Math.max(0.0, 1.0 - (double) (totalFrames - currentFrame) / fadeFrames);
                    }

                    // 应用淡入淡出效果
                    for (int i = 0; i < frame.samples.length; i++) {
                        Buffer buffer = frame.samples[i];
                        if (buffer instanceof ShortBuffer) {
                            ShortBuffer sb = (ShortBuffer) buffer;
                            for (int j = 0; j < sb.limit(); j++) {
                                short value = sb.get(j);
                                value = (short) (value * factor);
                                sb.put(j, value);
                            }
                        }
                    }
                }

                recorder.record(frame);
                currentFrame++;
                totalFrames++;
            }
        }

        // 更新上下文
        context.setAttribute("grabber", new FFmpegFrameGrabber("temp_fade.mp3"));
        log.info("Fade effect completed");
        return null;
    }

    @Override
    public String getStepName() {
        return "Fade";
    }
} 